//
//      Copyright 2011 richard collins
//
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#include "common.h"
#include "led_display.h"

//Now that the display done via an interupt we can store these tables in program memory as access speed is not an issue.
u8 numbers[10] PROGMEM = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d,0x07, 0x7f,0x6f};
u8 characters[26] PROGMEM =
{
	0x77,	//A
	0x7c,	//B
	0x39,	//C
	0x5e,	//D
	0x79,	//E
	0x71,	//F
	0x7d,	//G
	0x74,	//H
	0x30,	//I
	0x1e,	//J
	0x76,	//K
	0x38,	//L
	0x37,	//M
	0x54,	//N
	0x5c,	//O
	0x73,	//P
	0x67,	//Q
	0x50,	//R
	0x6d,	//S
	0x70,	//T
	0x1c,	//U
	0x3e,	//V
	0x7e,	//W
	0x76,	//X
	0x7f,	//Y
	0x5b,	//Z
};

//This is the 8 char display buffer that the printLCD func writes to and the interupt reads from.
static u8 displayBuffer[8];

//Turns a char into a bit pattern for a cell. Uses two tables in program space, although wondering if a big switch statement would be better?????
static u8 GetCharCode(char c)
{
	if( c == '-' )
	{
		return 64;
	}

	if( c == '.' )
	{
		return 128;
	}

	if( c >= '0' && c <= '9')
	{
		return pgm_read_byte(&(numbers[c - '0']));
	}

	if( c >= 'a' && c <= 'z' )
	{
		return pgm_read_byte(&(characters[c - 'a']));
	}

	if( c >= 'A' && c <= 'Z' )
	{
		return pgm_read_byte(&(characters[c - 'A']));
	}

	return 0;
}

//The cell that the interrupt is updating,
//we do one cell with each interrupt call and fire it fast that way the interrupt handler is not doing that much.
//Else it would need to block, which is very bad!
u8 currentCell = 0;
ISR(TIMER1_OVF_vect)
{
	//Seems sensitive of stuff being done between setting the write bit, writing the value and clearing the bit.
	//So I get the char to write and the mask before I send the data.
	unsigned char c = displayBuffer[currentCell];
	unsigned char b = ~(1<<currentCell);

	PORTD |= 1<<PD5;
	PORTA = b;//Bit pattern for which cell we are writing to.
	PORTD &= ~(1<<PD5);

	PORTD |= 1<<PD4;
	PORTA = c;//Value written.
	PORTD &= ~(1<<PD4);

	currentCell = (currentCell+1)&7;//Go to the next one for the next time we enter the interupt.
}


void LedDisplay_Open()
{
 	//Set all port A and D.
	//Port A is used to send data, port D is for control of data to send.
	PORTA = 255;//Start with all off.
	DDRA = 255;

	PORTD = 255;//Start with all off.(bit 6 if off turns the sound on)
	DDRD = 255;

	//Setup the timer interrupt.
	//Taken from the documentation @ http://www.drtak.org/teaches/ARC/cisp299_bot/book/book/node37.html
	cli(); // disable all interrupts
	TCCR1B = 0; // disable ticking
	TIMSK = (TIMSK & ~(0x3c)) | 0x04; // enable overflow interrupt
	TCNT1H = 0; // reset counter
	TCNT1L = 0;
	ICR1H = 3000U >> 8; // set overflow value
	ICR1L = 40000U & 0xff;
	TCCR1A = 0xfe; // 11 11 11 10, set channel configuration
	TCCR1B = 0x1a; // 00011010 start ticking
	sei(); // re enable interrupts
}

void LedDisplay_Print(const char *text)
{
	u8 n;
	for(n = 0 ; n < 8 ; n++)
	{
		displayBuffer[n] = GetCharCode(text[n]);
	}
}

